#ifndef GRAPHNODE_H
#define GRAPHNODE_H

#include <QList>

template <typename Type>
class GraphNode
{
public:
    explicit GraphNode (Type data, GraphNode<Type>* parentNode = 0);
    explicit GraphNode (GraphNode<Type>* parentNode = 0);
    ~GraphNode();

    void setData (Type data);
    const Type& data() const;
    Type& data();

    void setChildNode (GraphNode<Type>* childNode);
    void setChildNodes (QList<GraphNode<Type>*> childNodes);
    void addChildNode (GraphNode<Type>* childNode);
    void setParentNode (GraphNode<Type>* parentNode);
    void deleteChildNodes();

    QList<GraphNode<Type>*> childNodes() const;
    GraphNode<Type>* parentNode() const;
    bool hasChildNodes() const;

private:
    void trySetParent (GraphNode<Type>* childNode);

    Type m_data;
    QList<GraphNode<Type>*> m_childNodes;
    GraphNode<Type>* m_parentNode;
};

template <typename Type>
GraphNode<Type>::GraphNode (Type data, GraphNode<Type>* parentNode)
    : m_data(data), m_parentNode(parentNode)
{
}

template <typename Type>
GraphNode<Type>::GraphNode (GraphNode<Type>* parentNode)
    : m_parentNode(parentNode)
{
}

template <typename Type>
GraphNode<Type>::~GraphNode()
{
    qDeleteAll(m_childNodes);
}

template <typename Type>
void GraphNode<Type>::setData (Type data)
{
    m_data = data;
}

template <typename Type>
const Type& GraphNode<Type>::data() const
{
    return m_data;
}

template <typename Type>
Type& GraphNode<Type>::data()
{
    return m_data;
}

template <typename Type>
void GraphNode<Type>::setChildNode (GraphNode<Type>* childNode)
{
    Q_ASSERT(m_childNodes.isEmpty());
    m_childNodes.append(childNode);
    trySetParent(childNode);
}

template <typename Type>
void GraphNode<Type>::setChildNodes (QList<GraphNode<Type>*> childNodes)
{
    Q_ASSERT(m_childNodes.isEmpty());
    m_childNodes = childNodes;
    for (int i = 0; i < childNodes.size(); i++)
        trySetParent(childNodes.at(i));
}

template <typename Type>
void GraphNode<Type>::addChildNode (GraphNode<Type>* childNode)
{
    m_childNodes.append(childNode);
    trySetParent(childNode);
}

template <typename Type>
void GraphNode<Type>::setParentNode (GraphNode<Type>* parentNode)
{
    m_parentNode = parentNode;
}

template <typename Type>
void GraphNode<Type>::deleteChildNodes()
{
    qDeleteAll(m_childNodes);
    m_childNodes.clear();
}

template <typename Type>
QList<GraphNode<Type>*> GraphNode<Type>::childNodes() const
{
    return m_childNodes;
}

template <typename Type>
void GraphNode<Type>::trySetParent (GraphNode<Type>* childNode)
{
    if (!childNode->parentNode())
        childNode->setParentNode(this);
}

template <typename Type>
GraphNode<Type> *GraphNode<Type>::parentNode() const
{
    return m_parentNode;
}

template <typename Type>
bool GraphNode<Type>::hasChildNodes() const
{
    return !m_childNodes.isEmpty();
}

#ifndef QT_NO_DEBUG
#include <QDebug>
template <typename Type>
QDebug operator<< (QDebug debug, const GraphNode<Type>* node)
{
    debug << "GraphNode<Type> " << (void*)node << ", data " << node->data();
    return debug;
}
#endif

#endif // GRAPHNODE_H
